package cn.w.mac;

import java.util.concurrent.atomic.AtomicBoolean;

public class MacAddrOperator {

    static {
        System.loadLibrary("DeviceMac");
    }

    private static final MacAddrOperator ourInstance = new MacAddrOperator();

    public static MacAddrOperator getInstance() {
        return ourInstance;
    }

    private MacAddrOperator() {
        _init();
//        getMac();
    }

    /**
     * 执行初始化操作
     * <p>
     * 此部分不一定会执行内容，还是建议执行
     *
     * @return 0，如果成功；反之，失败
     */
    private native int _init();

    /**
     * 退出 MAC 部分功能
     *
     * @return 0，如果成功；反之，失败
     */
    private native int _close();

    /**
     * 设置 MAC 地址
     *
     * @param macAddr MAC 地址信息
     * @return 0，如果成功；其他，失败
     */
    private native int _setMac(byte[] macAddr, int length);

    /**
     * 获取当前设备的 MAC 地址信息
     *
     * @param macAddr 传递回来的 MAC 地址信息
     * @return 返回的数据长度，如果为 6 则为正常；反之，-1
     */
    private native int _getMac(byte[] macAddr);

    private final static AtomicBoolean readWriteControl = new AtomicBoolean(false);

    /**
     * 设置 MAC 地址信息
     * <p>
     * 此部分失败的原因：
     * 1. 已经设置过 MAC 地址，希望重新设置
     * 2. 数据部分异常，不符合数据标准
     *
     * @param macAddr 输入的MAC地址信息
     * @return true，如果设置成功；反之，false
     */
    public boolean setMac(String macAddr) {
        if (countMatches(macAddr, ":") == 5 || countMatches(macAddr, ":") == 6) {
            String[] splites = macAddr.split(":");

            byte[] macArray = null;

            if (splites.length == 6) {
                macArray = new byte[6];
                macArray[0] = (byte) Integer.parseInt(splites[0], 16);
                macArray[1] = (byte) Integer.parseInt(splites[1], 16);
                macArray[2] = (byte) Integer.parseInt(splites[2], 16);
                macArray[3] = (byte) Integer.parseInt(splites[3], 16);
                macArray[4] = (byte) Integer.parseInt(splites[4], 16);
                macArray[5] = (byte) Integer.parseInt(splites[5], 16);
                macAddr_ = byte2hexNum(macArray, ":", 6);
            } else if (splites.length == 7) {
                macArray = new byte[7];
                macArray[0] = (byte) Integer.parseInt(splites[0], 16);
                macArray[1] = (byte) Integer.parseInt(splites[1], 16);
                macArray[2] = (byte) Integer.parseInt(splites[2], 16);
                macArray[3] = (byte) Integer.parseInt(splites[3], 16);
                macArray[4] = (byte) Integer.parseInt(splites[4], 16);
                macArray[5] = (byte) Integer.parseInt(splites[5], 16);
                macArray[6] = (byte) Integer.parseInt(splites[6], 16);
                macAddr_ = byte2hexNum(macArray, ":", 6);
                if (macArray[6] == 0x00 || macArray[6] == (byte) 0xAA) {
                    isSystemEnabel = true;
                } else {
                    isSystemEnabel = false;
                }
            } else {
                return false;
            }

            int setResult;
            synchronized (readWriteControl) {
                setResult = _setMac(macArray, macArray.length);
            }

            switch (setResult) {
                case -1:
                    System.err.println("输入数据长度错误");
                    return false;
                case -2:
                    System.err.println("MAC 地址数据读取错误");
                    return false;
                case -3:
                    System.err.println("MAC地址已经存在，无法再次设置");
                    return false;
                case 0:
                    return true;
                default:
                    System.err.println("未知反馈值，返回错误");
                    break;
            }

        }
        return false;
    }

    private boolean isEmpty(final CharSequence cs) {
        return cs == null || cs.length() == 0;
    }

    private int countMatches(final CharSequence str, final CharSequence sub) {
        if (isEmpty(str) || isEmpty(sub)) {
            return 0;
        }
        int count = 0;
        int idx = 0;
        while ((idx = indexOf(str, sub, idx)) != -1) {
            count++;
            idx += sub.length();
        }
        return count;
    }

    private int indexOf(final CharSequence cs, final CharSequence searchChar, final int start) {
        return cs.toString().indexOf(searchChar.toString(), start);
    }

    private String macAddr_ = null;

    private boolean isSystemEnabel = true;

    /**
     * 当前系统是否处于使能状态
     *
     * @return true，系统可用；false，系统不可用
     */
    public boolean isSystemEnabel() {
        return isSystemEnabel;
    }

    /**
     * 获取当前设备的 MAC 地址
     *
     * @return 当前设备的 MAC 地址
     */
    public String getMac() {
        if (macAddr_ == null || "".equals(macAddr_)) {
            byte[] macAddr = new byte[7];
            int macLength;
            synchronized (readWriteControl) {
                macLength = _getMac(macAddr);
            }
            if (macLength == 6) {
                macAddr_ = byte2hexNum(macAddr, ":", 6);
            } else if (macLength == 7) {
                macAddr_ = byte2hexNum(macAddr, ":", 6);
                if (macAddr[6] == 0x00 || macAddr[6] == (byte) 0xAA) {
                    isSystemEnabel = true;
                } else {
                    isSystemEnabel = false;
                }
            } else if (macLength == 1) {
                if (macAddr[0] == 0x00 || macAddr[0] == (byte) 0xAA) {
                    isSystemEnabel = true;
                } else {
                    isSystemEnabel = false;
                }
            }
        }
        return macAddr_;
    }

    /**
     * 字符数组拼接，将 十进制数据 转化成 十六进制 数据
     *
     * @param buffer 数组
     * @param splite 分隔符
     * @return 拼接后的符合 MAC 地址规范的字符数组
     */
    private String byte2hexNum(byte[] buffer, String splite, int length) {
        if (buffer != null) {
            StringBuilder stringBuffer = new StringBuilder();
            for (int i = 0; i < length; i++) {
                String temp = Integer.toHexString(buffer[i] & 0xFF).toUpperCase();
                if (temp.length() == 1) {
                    temp = "0" + temp;
                    if (i != length - 1) {
                        temp += splite;
                    }
                } else if (temp.length() == 2) {
                    if (i != length - 1) {
                        temp += splite;
                    }
                }
                stringBuffer.append(temp);
            }
            return stringBuffer.toString();
        }
        return null;
    }

}
